home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / OWLSRC.PAK / APPLICAT.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  31.5 KB  |  1,230 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // Copyright (c) 1991, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   10.25  $
  6. //
  7. // Implementation of class TApplication. This defines the basic behavior
  8. // for ObjectWindows applications.
  9. //----------------------------------------------------------------------------
  10. #pragma hdrignore SECTION
  11. #include <owl/pch.h>
  12. #if !defined(OWL_APPLICAT_H)
  13. # include <owl/applicat.h>
  14. #endif
  15. #if !defined(OWL_FRAMEWIN_H)
  16. # include <owl/framewin.h>
  17. #endif
  18. #if !defined(OWL_DOCMANAG_H)
  19. # include <owl/docmanag.h>
  20. #endif
  21. #if !defined(OWL_APPDICT_H)
  22. # include <owl/appdict.h>
  23. #endif
  24. #if !defined(OWL_WINDOW_RH)
  25. # include <owl/window.rh>
  26. #endif
  27. #if defined(BI_COMP_BORLANDC) && !defined(__BWCC_H)
  28. # include <bwcc.h>
  29. #endif
  30.  
  31. OWL_DIAGINFO;
  32. #if defined(SECTION) && SECTION != 1
  33. DIAG_DECLARE_GROUP(OwlApp);        // General Application diagnostic group
  34. #endif
  35.  
  36. #if !defined(SECTION) || SECTION == 1
  37.  
  38. DIAG_DEFINE_GROUP_INIT(OWL_INI, OwlApp, 1, 0);
  39.  
  40. //
  41. // Static members for initialization of app prior to initial construction
  42. //
  43. HINSTANCE  TApplication::InitHInstance;
  44. HINSTANCE  TApplication::InitHPrevInstance;
  45. int        TApplication::InitCmdShow;
  46.  
  47. //
  48. //
  49. string&     
  50. TApplication::GetInitCmdLine()
  51. {
  52.   static string InitCmdLine;
  53.   return InitCmdLine;
  54. };
  55.  
  56. //
  57. // Global GetWindowPtr() message ID used for registered message
  58. //
  59. uint _OWLDATA GetWindowPtrMsgId = 0;
  60.  
  61. //
  62. // Constructor for use in OwlMain(). Gets members from statics set earlier by
  63. // a call to InitWinMainParams() in Owl's WinMain.
  64. //
  65. TApplication::TApplication(const char far* name, TModule*& gModule,
  66.                            TAppDictionary* appDict)
  67. :
  68.   TModule(name, InitHInstance, GetInitCmdLine().c_str()),
  69.   TMsgThread(TMsgThread::Current),
  70.   XBase(0), XState(0), DocManager(0),
  71.   Dictionary(appDict ? appDict : &(OWLGetAppDictionary()))
  72. {
  73.   TRACEX(OwlApp, OWL_CDLEVEL, "TApplication constructing @" << (void*)this);
  74.  
  75.   // Copy over values that were stashed in static members before this instance
  76.   // was constructed.
  77.   //
  78.   hPrevInstance = InitHPrevInstance;
  79.   nCmdShow = InitCmdShow;
  80.  
  81.   MainWindow = 0;
  82.   BWCCOn = Ctl3dOn = false;
  83.   BWCCModule = 0;
  84.   Ctl3dModule = 0;
  85.   CondemnedWindows = 0;
  86.   CmdLine = GetInitCmdLine();
  87.  
  88.   Dictionary->Add(this);
  89.   gModule = this;
  90.  
  91. #if defined(OWL2_COMPAT)
  92.   HAccTable = 0;
  93. #endif
  94.  
  95.   TRACEX(OwlApp, OWL_CDLEVEL, "TApplication constructed @" << (void*)this);
  96. }
  97.  
  98. //
  99. // Constructor for use in user defined WinMain() when all the args are
  100. // available
  101. //
  102. TApplication::TApplication(const char far* name,
  103.                            HINSTANCE       instance,
  104.                            HINSTANCE       prevInstance,
  105.                            const char far* cmdLine,
  106.                            int             cmdShow,
  107.                            TModule*&       gModule,
  108.                            TAppDictionary* appDict)
  109. :
  110.   TModule(name, instance, cmdLine),
  111.   TMsgThread(TMsgThread::Current),
  112.   XBase(0), XState(0), DocManager(0),
  113.   Dictionary(appDict ? appDict : &(OWLGetAppDictionary()))
  114. {
  115.   TRACEX(OwlApp, OWL_CDLEVEL, "TApplication constructing @" << (void*)this);
  116.   hPrevInstance = prevInstance;
  117.   nCmdShow = cmdShow;
  118.   MainWindow = 0;
  119.   BWCCOn = Ctl3dOn = false;
  120.   BWCCModule = 0;
  121.   Ctl3dModule = 0;
  122.   CondemnedWindows = 0;
  123.   CmdLine = cmdLine;
  124.  
  125.   Dictionary->Add(this);
  126.   gModule = this;
  127.  
  128. #if defined(OWL2_COMPAT)
  129.   HAccTable = 0;
  130. #endif
  131.  
  132.   TRACEX(OwlApp, OWL_CDLEVEL, "TApplication constructed @" << (void*)this);
  133. }
  134.  
  135. //
  136. //
  137. //
  138. TApplication::~TApplication()
  139. {
  140.   TRACEX(OwlApp, OWL_CDLEVEL, "TApplication destructing @" << (void*)this);
  141.  
  142.   DeleteCondemned();
  143.  
  144.   // Unregister ourselves from the Ctl3d DLL and/or the BWCC DLL if they are
  145.   // loaded.
  146.   //
  147.   if (Ctl3dModule) {
  148.     Ctl3dModule->Unregister(*this);
  149.     delete Ctl3dModule;
  150.   }
  151.   if (BWCCModule) {
  152.     BWCCModule->IntlTerm();
  153.     delete BWCCModule;
  154.   }
  155.  
  156.   // Delete the main window if still present, may be destroyed but not deleted
  157.   // Set MainWindow to 0 first to prevent it from calling ::PostQuitMessage
  158.   //
  159.   TWindow* mainWindow = SetMainWindow(0);
  160.   if (mainWindow) {
  161.     mainWindow->Destroy();
  162.     delete mainWindow;
  163.   }
  164.  
  165.   delete (TStreamableBase*)DocManager;// cast to avoid ref to docmgr if not used
  166.  
  167.   // Remove this app from the application dictionary that it is in
  168.   //
  169.   Dictionary->Remove(this);
  170.   delete XBase;   // remove any exception copy
  171.  
  172.   TRACEX(OwlApp, OWL_CDLEVEL, "TApplication destructed @" << (void*)this);
  173. }
  174.  
  175. //
  176. // Popup a mesasge box. Automatically deals with BWCC and Ctl3d if enabled for
  177. // this app.
  178. //
  179. int
  180. TApplication::MessageBox(HWND hParentWnd,
  181.                          const char far* text,
  182.                          const char far* caption,
  183.                          uint            type)
  184. {
  185.   // Default caption to this application's name
  186.   //
  187.   if (!caption)
  188.     caption = GetName();
  189.  
  190.   // If no parent is supplied need to use task modal to disable all toplevel
  191.   // windows in this task.
  192.   //
  193.   if (!hParentWnd && !(type & MB_SYSTEMMODAL))
  194.     type |= MB_TASKMODAL;
  195.  
  196.   // Use the BWCC message box if BWCC is enabled
  197.   //
  198. #if defined(BI_COMP_BORLANDC)
  199.   if (BWCCEnabled() && GetBWCCModule()) {
  200.     return GetBWCCModule()->MessageBox(hParentWnd, text, caption, type);
  201.   }
  202.   else
  203. #endif
  204.   // Otherwise, 3d-ize the message box if ctl3d is enabled
  205.   //
  206. #if !defined(BI_COMP_MSC)
  207.   {
  208.     EnableCtl3dAutosubclass(true);
  209.     int retValue = ::MessageBox(hParentWnd, text, caption, type);
  210.     EnableCtl3dAutosubclass(false);
  211.     return retValue;
  212.   }
  213. #else
  214.   return ::MessageBox(hParentWnd, text, caption, type);
  215. #endif
  216. }
  217.  
  218. //
  219. // Handle initialization for the first executing instance of the OWL
  220. // application. Under Win32, every app instance is treated as the first.
  221. //
  222. // Derived classes can override this to perform app initialization, or they
  223. // can use the derived class constructor.
  224. //
  225. void
  226. TApplication::InitApplication()
  227. {
  228.   TRACEX(OwlApp, 1, "TApplication::InitApplication() called @" << (void*)this);
  229. }
  230.  
  231. //
  232. // Handle initialization for each executing instance of the OWL application.
  233. // Derived classes can override this to perform initialization for each
  234. // instance.
  235. //
  236. // This default implementation calls InitMainWindow() to initialize the
  237. // main window, and then if successful, creates and shows it. A
  238. // TXInvalidMainWIndow exception is thrown if no main window is set during
  239. // InitMainWindow()
  240. //
  241. void
  242. TApplication::InitInstance()
  243. {
  244.   TMsgThread::InitInstance();
  245.  
  246.   TRACEX(OwlApp, 1, "TApplication::InitInstance() called @" << (void*)this);
  247.  
  248.   InitMainWindow();
  249.  
  250.   if (MainWindow) {
  251.     MainWindow->SetFlag(wfMainWindow);
  252.     MainWindow->Create();
  253.     MainWindow->ShowWindow(nCmdShow);
  254.   }
  255.   else
  256.     TXInvalidMainWindow::Raise();
  257. }
  258.  
  259. //
  260. // Initialize the application's main window. Derived classes should override
  261. // this to construct, initialize and set the main window using SetMainWindow().
  262. //
  263. // Default main window is a plain TFrameWindow with a title that is the same
  264. // as this application's name
  265. //
  266. void
  267. TApplication::InitMainWindow()
  268. {
  269.   SetMainWindow(new TFrameWindow(0, GetName()));
  270. }
  271.  
  272. //
  273. // Handle termination for each executing instance of the application. Called
  274. // at the end of a Run() with the final return status.
  275. //
  276. int
  277. TApplication::TermInstance(int status)
  278. {
  279.   TRACEX(OwlApp, 1, "TApplication::TermInstance() called @" << (void*)this);
  280.  
  281.   return TMsgThread::TermInstance(status);
  282. }
  283.  
  284. //
  285. // Set (or reset) the main window. Return, but do not destroy the previous
  286. // main window.
  287. //
  288. TFrameWindow*
  289. TApplication::SetMainWindow(TFrameWindow* window)
  290. {
  291.   if (MainWindow) {
  292.     MainWindow->ClearFlag(wfMainWindow);
  293.     uint32 style = MainWindow->GetExStyle();
  294.     if (style & WS_EX_APPWINDOW)
  295.       MainWindow->SetExStyle(style & ~WS_EX_APPWINDOW);
  296.   }
  297.  
  298.   TFrameWindow* oldMainWindow = MainWindow;
  299.   MainWindow = window;
  300.  
  301.   if (MainWindow) {
  302.     MainWindow->SetFlag(wfMainWindow);
  303.     uint32 style = MainWindow->GetExStyle();
  304.     if (!(style & WS_EX_APPWINDOW))
  305.       MainWindow->SetExStyle(style | WS_EX_APPWINDOW);
  306.   }
  307.   return oldMainWindow;
  308. }
  309.  
  310. //
  311. // Set (or resets) the document manager, return the previous one if present
  312. //
  313. TDocManager*
  314. TApplication::SetDocManager(TDocManager* docManager)
  315. {
  316.   TDocManager* oldDocManager = DocManager;
  317.   DocManager = docManager;
  318.   return oldDocManager;
  319. }
  320.  
  321. #if defined(BI_MULTI_THREAD_RTL)
  322. //
  323. // Override TEventHandler::Dispatch() to handle multi-thread synchonization
  324. //
  325. TResult TApplication::Dispatch(TEventInfo& info, TParam1 p1, TParam2 p2)
  326. {
  327.   TApplication::TQueueLock lock(*this);
  328.   return TEventHandler::Dispatch(info, p1, p2);
  329. }
  330. #endif
  331.  
  332. //
  333. // Run this application, return when application terminates
  334. //
  335. // Initialize instances, create and display their main window (calls
  336. // InitApplication for the first executing instance and calls InitInstance for
  337. // all instances). Run the application's message loop. Each of the virtual
  338. // functions called are expected to throw an exception if there is an error.
  339. //
  340. // Exceptions that are not handled, i.e. status remains non-zero, are
  341. // propagated out of this function. Msg queue is still flushed & TermInstance
  342. // called.
  343. //
  344. int
  345. TApplication::Run()
  346. {
  347.   int status;
  348.   try {
  349.     try {
  350.       if (!MainWindow) {
  351.         if (!hPrevInstance)
  352.           InitApplication();
  353.         InitInstance();
  354.       }
  355.       LoopRunning = true;
  356.       status = MessageLoop();
  357.     }
  358.     catch (TXOwl& x) {
  359.       status = x.Unhandled(this, 0);
  360.       if (status)
  361.         throw;
  362.     }
  363.     catch (xmsg& x) {
  364.       status = Error(x, 0);
  365.       if (status)
  366.         throw;
  367.     }
  368. #if !defined(BI_NO_NEW_CASTS)
  369.     catch (Bad_cast& x) {
  370.       xmsg msg(string(typeid(x).name()));
  371.       status = Error(msg, 0);
  372.       if (status)
  373.         throw;
  374.     }
  375.     catch (Bad_typeid& x) {
  376.       xmsg msg(string(typeid(x).name()));
  377.       status = Error(msg, 0);
  378.       if (status)
  379.         throw;
  380.     }
  381. #endif
  382.   }
  383.   catch (...) {
  384.     FlushQueue();
  385.     LoopRunning = false;
  386.     TermInstance(status);
  387.     throw;
  388.   }
  389.  
  390.   FlushQueue();
  391.  
  392.   LoopRunning = false;
  393.   return TermInstance(status);
  394. }
  395.  
  396. //
  397. // Start this application and return immediately. Used for component DLLs
  398. //
  399. // Initializes instances, creating and displaying their main window (calls
  400. // InitApplication for the first executing instance and calls InitInstance for
  401. // all instances). Each of the virtual functions called are expected to throw
  402. // an exception if there is an error. Does not run message loop.
  403. //
  404. int
  405. TApplication::Start()
  406. {
  407.   int status = 0;
  408.   TRY {
  409.     if (!hPrevInstance)
  410.       InitApplication();
  411.     InitInstance();
  412.   }
  413.   CATCH( (TXOwl& x) {status = x.Unhandled(this, 0);})
  414.   CATCH( (xmsg& x) {status = Error(x, 0);})
  415. #if !defined(BI_NO_NEW_CASTS)
  416.   
  417.   CATCH( (Bad_cast& x)
  418.   {
  419.     xmsg msg(string(typeid(x).name()));
  420.     status = Error(msg, 0);
  421.   })
  422.   CATCH( (Bad_typeid& x)
  423.   {
  424.     xmsg msg(string(typeid(x).name()));
  425.     status = Error(msg, 0);
  426.   })
  427. #endif
  428.  
  429.   return status;
  430. }
  431.  
  432. //
  433. // General message loop: retrieves and processes messages from the OWL
  434. // application's message queue using PumpWaitingMessages() until
  435. // BreakMessageLoop becomes true. Catches and defers to handlers a number of
  436. // exceptions.
  437. //
  438. // Call IdleAction() when there are no messages
  439. //
  440. int
  441. TApplication::MessageLoop()
  442. {
  443.   long idleCount = 0;
  444.  
  445.   MessageLoopResult = 0;
  446.   while (!BreakMessageLoop) {      
  447.     try {
  448.       if (!IdleAction(idleCount++))
  449.         ::WaitMessage();             // allow system to go idle
  450.       if (PumpWaitingMessages())     // pumps any waiting messages
  451.         idleCount = 0;
  452.     }
  453.     catch (TXOwl& x) {
  454.       MessageLoopResult = x.Unhandled(this, IDS_OKTORESUME);
  455.       if (MessageLoopResult != 0) {
  456.         ::PostQuitMessage(MessageLoopResult);
  457.         break;
  458.       }
  459.     }
  460.     catch (xmsg& x) {
  461.       MessageLoopResult = Error(x, 0, IDS_OKTORESUME);
  462.       if (MessageLoopResult != 0) {
  463.         ::PostQuitMessage(MessageLoopResult);
  464.         break;
  465.       }
  466.     }
  467. #if !defined(BI_NO_NEW_CASTS)
  468.     catch (Bad_cast& x) {
  469.       xmsg msg(string(typeid(x).name()));
  470.       MessageLoopResult = Error(msg, 0, IDS_OKTORESUME);
  471.       if (MessageLoopResult != 0) {
  472.         ::PostQuitMessage(MessageLoopResult);
  473.         break;
  474.       }
  475.     }
  476.     catch (Bad_typeid& x) {
  477.       xmsg msg(string(typeid(x).name()));
  478.       MessageLoopResult = Error(msg, 0, IDS_OKTORESUME);
  479.       if (MessageLoopResult != 0) {
  480.         ::PostQuitMessage(MessageLoopResult);
  481.         break;
  482.       }
  483.     }
  484.   }
  485. #endif
  486.   BreakMessageLoop = false;
  487.   return MessageLoopResult;
  488. }
  489.  
  490. //
  491. // Called each time there are no messages in the queue. Idle count is
  492. // incremented each time, & zeroed when messages are pumped. Return
  493. // whether or not more processing needs to be done.
  494. //
  495. // Default behavior is to give the main window an opportunity to do idle
  496. // processing by invoking its IdleAction() member function when
  497. // "idleCount" is 0
  498. //
  499. bool
  500. TApplication::IdleAction(long idleCount)
  501. {
  502.   TRACEX(OwlApp, 1, "TApplication::IdleAction() called @" << (void*)this <<
  503.                     " idleCount " << idleCount);
  504.   if (MainWindow)
  505.     return MainWindow->IdleAction(idleCount);
  506.   return false;
  507. }
  508.  
  509. //
  510. // Called for each message that is pulled from the queue, to perform all
  511. // translation & dispatching.
  512. // dispatched.
  513. // Return true to drop out of pump
  514. //
  515. bool
  516. TApplication::ProcessMsg(MSG& msg)
  517. {
  518.   // Let the app preprocess the message. If it is not eaten, then translate
  519.   // it, & dispatch it. If no HWND, then first find/dispatch it directly
  520.   // to the app (for PostAppMessage() functionality)
  521.   //
  522.   if (!ProcessAppMsg(msg)) {
  523.     ::TranslateMessage(&msg);
  524.     if (!msg.hwnd) {
  525.       TEventInfo cmdEventInfo(msg.message, msg.wParam);
  526.       if (Find(cmdEventInfo)) {
  527.         Dispatch(cmdEventInfo, msg.wParam, msg.lParam);
  528.         return true;
  529.       }
  530.       else {
  531.         TEventInfo eventInfo(msg.message);
  532.         if (Find(eventInfo)) {
  533.           Dispatch(eventInfo, msg.wParam, msg.lParam);
  534.           return true;
  535.         }
  536.       }
  537.     }
  538.     ::DispatchMessage(&msg);
  539.     DeleteCondemned();
  540.     ResumeThrow();
  541.   }
  542.   return false;
  543. }
  544.  
  545. //
  546. // Called after each message is pulled from the queue, and before it is
  547. // dispatched. Return true if the message was handled completely here.
  548. //
  549. bool
  550. TApplication::ProcessAppMsg(MSG& msg)
  551. {
  552.   // Start with the window that the event was destined for and allow it
  553.   // and its parent (and its parent...) an opportunity to preprocess the
  554.   // event
  555.   //
  556.   for (HWND hWnd = msg.hwnd; hWnd; hWnd = ::GetParent(hWnd)) {
  557. #if defined(BI_PLAT_WIN32)
  558.     // NT seems very picky about calls to ::GetWindowThreadProcessId
  559.     // with the HWND of the desktop. Hence we'll abort this loop
  560.     // when encountering the desktop. Specially useful when dealing with
  561.     // DropDown[List] ComboBoxes thunked by OWL when hit the ComboLBox 
  562.     // window which is parented to the Desktop.
  563.     //
  564.     class _TDesktopWindow {
  565.       public:
  566.        _TDesktopWindow() : hwnd(::GetDesktopWindow()){}
  567.         operator  HWND() const { return hwnd; }
  568.         HWND      hwnd;
  569.     };
  570.     const static _TDesktopWindow deskTopHwnd;
  571.     if (hWnd == deskTopHwnd)
  572.       break;
  573. #endif
  574.  
  575.     TWindow*  win = GetWindowPtr(hWnd);
  576.  
  577.     if (win && win->PreProcessMsg(msg))
  578.       return true;
  579.   }
  580.  
  581. #if defined(OWL2_COMPAT)
  582.   // For compatability with OWL 1.0, check the application's accelerator
  583.   // table if it is being used.
  584.   //
  585.   if (HAccTable && MainWindow)
  586.     return ::TranslateAccelerator(MainWindow->GetHandle(), HAccTable, &msg);
  587. #endif
  588.  
  589.   return false;
  590. }
  591.  
  592. //
  593. // Should call this after each message dispatch when TApplication's message
  594. // loop is not being used.
  595. //
  596. void
  597. TApplication::PostDispatchAction()
  598. {
  599.   DeleteCondemned();
  600.   ResumeThrow();
  601.  
  602.   MSG msg;
  603.   if (!::PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE))
  604.     IdleAction(0);
  605. }
  606.  
  607. #if defined(BI_PLAT_WIN16) || defined(WIN32S_SUPPORT)
  608. //
  609. // Suspend throw functions store away a caught exception to allow foreign code
  610. // to be re-entered. Call ResumeThrow() to rethrow the exception, if any, upon
  611. // return from the foreign code.
  612. //
  613.  
  614. //
  615. // Save off xalloc information to be rethrown later
  616. //
  617. void
  618. TApplication::SuspendThrow(xalloc& x)
  619. {
  620.   XString = x.why();
  621.   XSize   = x.requested();
  622.   XState |= xsAlloc;
  623. }
  624.  
  625. //
  626. // Save off xmsg information to be rethrown later
  627. //
  628. void
  629. TApplication::SuspendThrow(xmsg& x)
  630. {
  631.   XString = x.why();
  632.   XState |= xsMsg;
  633. }
  634.  
  635. //
  636. // Save off a copy of a TXBase object to be rethrown later
  637. //
  638. void
  639. TApplication::SuspendThrow(TXBase& x)
  640. {
  641.   delete XBase;       // Remove any previous exception
  642.   XBase = x.Clone();
  643.   XState |= xsBase;
  644. }
  645.  
  646. //
  647. // Sets bit flag to log exception
  648. //
  649. void
  650. TApplication::SuspendThrow(int flag)
  651. {
  652.   XState |= (flag & (xsBadCast | xsBadTypeid | xsUnknown));
  653. }
  654.  
  655. //
  656. // Check and rethrows suspended exceptions if one exists, otherwise does
  657. // nothing
  658. //
  659. void
  660. TApplication::ResumeThrow()
  661. {
  662.   if (XState) {
  663.     if (XState & xsBase) {
  664.       XState &= ~xsBase;
  665.       XBase->Throw();  // must be deleted later
  666.     }
  667.     if (XState & xsAlloc) {
  668.       XState &= ~xsAlloc;
  669.       THROW( xalloc(XString,XSize) );
  670.     }
  671.     if (XState & xsMsg) {
  672.       XState &= ~xsMsg;
  673.       THROW( xmsg(XString) );
  674.     }
  675.     if (XState & xsUnknown) {
  676.       XState &= ~xsUnknown;
  677.       THROW( xmsg(string()) );
  678.     }
  679. #if !defined(BI_NO_NEW_CASTS)
  680.     if (XState & xsBadCast) {
  681.       XState &= ~xsBadCast;
  682.       THROW( Bad_cast() );
  683.     }
  684.     if (XState & xsBadTypeid) {
  685.       XState &= ~xsBadTypeid;
  686.       THROW( Bad_typeid() );
  687.     }
  688. #endif
  689.   }
  690. }
  691. #endif  // #if defined(BI_PLAT_WIN16) || defined(WIN32S_SUPPORT)
  692.  
  693. DEFINE_RESPONSE_TABLE_ENTRIES(TApplication)
  694.   EV_COMMAND(CM_EXIT, CmExit),
  695. END_RESPONSE_TABLE;
  696.  
  697. //
  698. // Close down main window if application receives a CM_EXIT command.
  699. //
  700. void
  701. TApplication::CmExit()
  702. {
  703.   TFrameWindow* frame = GetMainWindow();
  704.   if (frame) {
  705.     frame->SendMessage(WM_CLOSE);
  706.     DeleteCondemned();
  707.   }
  708. }
  709.  
  710. //
  711. // TApplication defers event handling to DocManager first if one has been
  712. // installed.
  713. //
  714. bool
  715. TApplication::Find(TEventInfo &eventInfo, TEqualOperator equal)
  716. {
  717.   // Doc manager gets a chance to handle the event first
  718.   //
  719.   bool retVal = DocManager ? DocManager->Find(eventInfo, equal) : false;
  720.   if (retVal == false) {
  721.     eventInfo.Object = (GENERIC*)this;
  722.     retVal = SearchEntries((TGenericTableEntry __RTFAR*)__entries, eventInfo, equal) ||
  723.              TEventHandler::Find(eventInfo, equal);
  724.   }
  725.   return retVal;
  726. }
  727.  
  728. //
  729. // Determine whether the application can be closed.
  730. // Makes sure the MainWindow can close & doc manager can close.
  731. //
  732. bool
  733. TApplication::CanClose()
  734. {
  735.   TEventInfo eventInfo(WM_OWLCANCLOSE);
  736.   return (!MainWindow || MainWindow->CanClose())
  737.       && (!DocManager ||!DocManager->Find(eventInfo)
  738.                       || DocManager->Dispatch(eventInfo, 0, 0));
  739. }
  740.  
  741. //
  742. // Called by the main window to provide an oportunity to preprocess the main
  743. // window's menubar before it is installed.
  744. // Normally delegated to the doc manager to install a file menu as needed
  745. //
  746. void
  747. TApplication::PreProcessMenu(HMENU hMenubar)
  748. {
  749.   TEventInfo eventInfo(WM_OWLPREPROCMENU);
  750.   if (DocManager && DocManager->Find(eventInfo)) {
  751.     DocManager->Dispatch(eventInfo, TParam1(hMenubar), 0);
  752.     MainWindow->DrawMenuBar();
  753.   }
  754. }
  755.  
  756. //
  757. // Condemn a window to be deleted the at the next available safe time.
  758. // Adds the window to a normal single linked list
  759. //
  760. // Condemned windows should be removed if they are destructed in the mean 
  761. // time thru some other mechanism (i.e. stack, aggregate, etc)
  762. //
  763. void
  764. TApplication::Condemn(TWindow* win)
  765. {
  766.   TRACEX(OwlApp, 1, "Condemning window @" << (void*)win << *win);
  767.   win->SetParent(0);
  768.  
  769. #if 0
  770.  
  771.   // The following logic is from previous versions of ObjectWindows.
  772.   // It results in LIFO destructions which is somewhat unfair.
  773.   // However, we'll keep this code around in case previous applications 
  774.   // relied on this destruction order
  775.   //
  776.   win->SetNext(CondemnedWindows);
  777.   CondemnedWindows = win;
  778.  
  779. #else
  780.  
  781.   // Insert the new window to be deleted at the end of the list
  782.   //
  783.   win->SetNext(0);
  784.   if (CondemnedWindows) {
  785.     TWindow* eol = CondemnedWindows;
  786.     while (eol->Next())
  787.       eol = eol->Next();
  788.     eol->SetNext(win);
  789.   } else {
  790.     CondemnedWindows = win;
  791.   }
  792.  
  793. #endif
  794. }
  795.  
  796. //
  797. // Remove a condemned window from the list.
  798. //
  799. void
  800. TApplication::Uncondemn(TWindow* win)
  801. {
  802.   if (win && CondemnedWindows) {
  803.     TWindow* w = 0;
  804.     if (CondemnedWindows != win)
  805.       for (w = CondemnedWindows; w->Next() != win; w = w->Next())
  806.         if (!w->Next())
  807.           return;
  808.  
  809.     TRACEX(OwlApp, 1, "Uncondemning window @" << (void*)win << *win);
  810.     if (w)
  811.       w->SetNext(win->Next());
  812.     else
  813.       CondemnedWindows = win->Next();
  814.   }
  815. }
  816.  
  817. //
  818. // Walk the condemned window list & delete each window. Assumes that the
  819. // windows were constructed using 'new'
  820. //
  821. void
  822. TApplication::DeleteCondemned()
  823. {
  824.   while (CondemnedWindows) {
  825.     TRACEX(OwlApp, 1, "Deleting condemned window @" << CondemnedWindows << *CondemnedWindows);
  826.     TWindow* next = CondemnedWindows->Next();
  827.     delete CondemnedWindows;
  828.     CondemnedWindows = next;
  829.   }
  830. }
  831.  
  832. //----------------------------------------------------------------------------
  833.  
  834. //
  835. //
  836. //
  837. TXInvalidMainWindow::TXInvalidMainWindow()
  838. :
  839.   TXOwl(IDS_INVALIDMAINWINDOW)
  840. {
  841. }
  842.  
  843. #if defined(BI_NO_COVAR_RET)
  844. TXBase*
  845. #else
  846. TXInvalidMainWindow*
  847. #endif
  848. TXInvalidMainWindow::Clone()
  849. {
  850.   return new TXInvalidMainWindow(*this);
  851. }
  852.  
  853. //
  854. //
  855. //
  856. void
  857. TXInvalidMainWindow::Throw()
  858. {
  859.   THROW( *this );
  860. }
  861.  
  862. //
  863. // Throws a TXInvalidMainWindow exception.
  864. //
  865. void
  866. TXInvalidMainWindow::Raise()
  867. {
  868.   TXInvalidMainWindow().Throw();
  869. }
  870.  
  871. #endif
  872. //----------------------------------------------------------------------------
  873. #if !defined(SECTION) || SECTION == 2
  874.  
  875. struct TEnumInfo {
  876.   HWND      ModalWnd; // The window being made modal if needed
  877.   short     Count;    // Count of windows in Wnds below
  878.   HWND*     Wnds;     // list of windows that were disabled
  879. };
  880. static TEnumInfo* stackTop = 0; // points to topmost enuminfo in BeginModal calls
  881.  
  882. //
  883. // Enum[Thread/Task]Windows callback. Counts or disables given window based on
  884. // whether or not window list has been allocated yet.
  885. //
  886. static bool CALLBACK OWL_EXPORT16
  887. disableWnds(HWND hWnd, TEnumInfo far* ei)
  888. {
  889.   if (!(::GetWindowLong(hWnd, GWL_STYLE) & WS_CHILD)) {
  890.     if (hWnd != ei->ModalWnd && ::IsWindowEnabled(hWnd)) {
  891.       if (!ei->Wnds) {
  892.         ei->Count++;  // no buffer yet, we are just counting
  893.       }
  894.       else {
  895.         *(ei->Wnds++) = hWnd;
  896.         ::EnableWindow(hWnd, false);
  897.       }
  898.     }
  899.   }
  900.   return true;
  901. }
  902.  
  903. //
  904. // Terminate the modal state initiated by BeginModal. Needs topmost ei block,
  905. // and cleans the block up as needed inorder to be safe to be called twice.
  906. //
  907. static void termModal(TEnumInfo& ei)
  908. {
  909.   // Re-enable window(s) that are disabled in BeginModal()
  910.   //
  911.   if (ei.Wnds) {
  912.     for (HWND* hWnd = ei.Wnds; *hWnd; hWnd++)
  913.       ::EnableWindow(*hWnd, true);
  914.     delete[] ei.Wnds;
  915.     ei.Wnds = 0;
  916.   }
  917.   else {
  918.     if (ei.ModalWnd && IsWindow(ei.ModalWnd)) {
  919.       ::EnableWindow(ei.ModalWnd, true);
  920.       ei.ModalWnd = 0;
  921.     }
  922.   }
  923. }
  924.  
  925. //
  926. // Go modal and enter a message loop until a quit message goes by.
  927. // the flag values determine how window is used:
  928. //
  929. //   MB_APPLMODAL -   window is the owner to disable (if 0, none are disabled)
  930. //   MB_TASKMODAL -   window is the window to make modal,
  931. //                    all other top level windows are disabled
  932. //   MB_SYSTEMMODAL - window is the window to make system modal (16-bit only)
  933. //
  934. // return -1 on errors
  935. //
  936. int
  937. TApplication::BeginModal(TWindow* window, int flags)
  938. {
  939.   TEnumInfo  ei = { 0, 0, 0 };
  940.   TEnumInfo* lastStackTop = stackTop; // Keep last stackTop to restore later
  941.   stackTop = &ei;                     // Point stackTop to topmost ei
  942.  
  943. #if defined(BI_PLAT_WIN32)
  944.   // The concept of SYSTEM MODAL applies only to the 16-bit environment of
  945.   // Windows. The semantics of TASKMODAL is the closest to SYSMODAL in
  946.   // 32-bit - specially in relation to the meaning of the 'window' parameter.
  947.   // So we'll coerce SYSTEM MODAL to TASK MODAL
  948.   //
  949.   if (flags & MB_SYSTEMMODAL) {
  950.     flags &= ~MB_SYSTEMMODAL;
  951.     flags |=  MB_TASKMODAL;
  952.   }
  953. #endif
  954.  
  955.   // Check modal state
  956.   //
  957.   if (flags & MB_TASKMODAL) {
  958.     // Save the window to make modal
  959.     //
  960.     if (window)
  961.       ei.ModalWnd = window->GetHandle();  
  962.  
  963.     // Count windows to disable
  964.     //
  965. #if   defined(BI_PLAT_WIN32)
  966.     if (!EnumThreadWindows(GetCurrentThreadId(), (WNDENUMPROC)disableWnds,
  967.                            TParam2((TEnumInfo far*)&ei)))
  968.       return -1;
  969. #elif defined(BI_PLAT_WIN16)
  970.     if (!EnumTaskWindows(GetCurrentTask(), (WNDENUMPROC)disableWnds,
  971.                          TParam2((TEnumInfo far*)&ei)))
  972.       return -1;
  973. #endif
  974.  
  975.     // Allocate list of windows to disable, disable windows that are
  976.     // enabled and then stuff them into the list.
  977.     //
  978.     HWND* hWnds = ei.Wnds = new HWND[ei.Count + 1];
  979.     memset(ei.Wnds, 0, sizeof(TModule::THandle)*(ei.Count + 1));
  980.  
  981. #if   defined(BI_PLAT_WIN32)
  982.     EnumThreadWindows(GetCurrentThreadId(), (WNDENUMPROC)disableWnds,
  983.                       TParam2((TEnumInfo far*)&ei));
  984. #elif defined(BI_PLAT_WIN16)
  985.     EnumTaskWindows(GetCurrentTask(), (WNDENUMPROC)disableWnds,
  986.                     TParam2((TEnumInfo far*)&ei));
  987. #endif
  988.  
  989.     ei.Wnds = hWnds;  // Restore alloc'd pointer since enumerator bumps it
  990.   }
  991. #if defined(BI_PLAT_WIN16)
  992.   else if (flags & MB_SYSTEMMODAL)
  993.     window->SetSysModalWindow();
  994. #endif
  995.  
  996.   else if (window) {
  997.  
  998.     // In MB_APPMODAL mode, we simply disable the window specified
  999.     //
  1000.     ei.ModalWnd = window->GetHandle();  // Remember who to re-enable later
  1001.     CHECK(ei.ModalWnd);
  1002.     window->EnableWindow(false);
  1003.   }
  1004.  
  1005.   // Enter message loop, saving & restoring the current status & getting the
  1006.   // returned result.
  1007.   //
  1008.   int result;
  1009.   TRY {
  1010.     result = MessageLoop();
  1011.   }
  1012.   CATCH( (...) {
  1013.     termModal(ei);
  1014.     stackTop = lastStackTop;
  1015.     RETHROW;
  1016.   })
  1017.   stackTop = lastStackTop;
  1018.   termModal(ei);            // Just in case termModal was missed in EndModal
  1019.  
  1020.   // Return the result from the modal window's EndModal call
  1021.   //
  1022.   return result;
  1023. }
  1024.  
  1025. //
  1026. // Cause the current modal message loop to break and have it return a result
  1027. // Re-enable the disabled windows here, if the EnumInfo is available.
  1028. //
  1029. void
  1030. TApplication::EndModal(int result)
  1031. {
  1032.   MessageLoopResult = result;
  1033.   BreakMessageLoop = true;
  1034.   if (stackTop)
  1035.     termModal(*stackTop);
  1036. }
  1037.  
  1038. #endif
  1039. //----------------------------------------------------------------------------
  1040. #if !defined(SECTION) || SECTION == 3
  1041.  
  1042. //
  1043. // Predefined DLLs that TApplication knows how to find.
  1044. //
  1045. #if defined(BI_PLAT_WIN32)
  1046.   const char BwccDllName[]  = "BWCC32.DLL";
  1047.   const char Ctl3dDllName[] = "CTL3D32.DLL";
  1048. #elif defined(BI_PLAT_WIN16)
  1049.   const char BwccDllName[]  = "BWCC.DLL";
  1050.   const char Ctl3dDllName[] = "CTL3DV2.DLL";
  1051. #endif
  1052.  
  1053. //
  1054. // Load the BWCC DLL if needed & set the BWCC on flag according to 'enable'
  1055. // Library is not free'd on disable to reduce re-loads if enabling on the fly
  1056. //
  1057. void
  1058. TApplication::EnableBWCC(bool enable, uint language)
  1059. {
  1060.   if (enable) {
  1061.     if (!BWCCModule) {
  1062.       try {
  1063.         BWCCModule = new TBwccDll();
  1064.         BWCCModule->IntlInit(language);
  1065.         BWCCModule->Register(GetHandle());
  1066.  
  1067.         WARNX(OwlApp, BWCCModule->GetVersion() < BWCCVERSION, 0, \
  1068.               "Old version of BWCC DLL found");
  1069.       }
  1070.       catch (...) {
  1071.         TRACEX(OwlApp, 0, "Unable to create instance of TBwccDll");
  1072.         return;
  1073.       }
  1074.     }
  1075.   }
  1076.   BWCCOn = enable;
  1077. }
  1078.  
  1079. //
  1080. // Enable or disable the use of the CTL3D DLL. Loads it on demand if needed.
  1081. //
  1082. void
  1083. TApplication::EnableCtl3d(bool enable)
  1084. {
  1085.   // As per Article Q125684 of Microsoft Development Library:
  1086.   // "If major version is 4 or greater, the application should not 
  1087.   //  implement CTL3D".
  1088.   //      'How to Use CTL3D Under the Windows 95 Operating System'
  1089.   //
  1090.   if (TSystem::GetMajorVersion() >= 4)
  1091.     return;
  1092.  
  1093.   // Load the Ctl3d DLL if needed & register our instance
  1094.   //
  1095.   if (enable) {
  1096.     if (!Ctl3dModule) {
  1097.       try {
  1098.         Ctl3dModule = new TCtl3dDll();
  1099.         Ctl3dModule->Register(*this);
  1100.       }
  1101.       catch (...) {
  1102.         TRACEX(OwlApp, 0, "Unable to create instance of TCtl3dDll");
  1103.         return;
  1104.       }
  1105.     }
  1106.   }
  1107.   Ctl3dOn = enable;
  1108. }
  1109.  
  1110. //
  1111. // Enable or disable Ctl3d's use of auto-subclassing.
  1112. //
  1113. // Caller should turn on autosubclassing before creating a non-owl dialog to
  1114. // make it 3d, & turn it off immediatly after.
  1115. //
  1116. void
  1117. TApplication::EnableCtl3dAutosubclass(bool enable)
  1118. {
  1119.   if (Ctl3dEnabled()) {
  1120.     if (enable) {
  1121.       Ctl3dModule->Register(*this);
  1122.       Ctl3dModule->AutoSubclass(*this);
  1123.     }
  1124.     else {
  1125.       Ctl3dModule->Unregister(*this);
  1126.     }
  1127.   }
  1128. }
  1129.  
  1130. //
  1131. // Load the BWCC DLL dynamically.
  1132. // Bind the member functions to the exported functions.
  1133. //
  1134. TBwccDll::TBwccDll()
  1135. :
  1136.   TModule(BwccDllName, true, true),
  1137.  
  1138.   IntlInit(*this, "BWCCIntlInit"),
  1139.   Register(*this, "BWCCRegister"),
  1140.   IntlTerm(*this, "BWCCIntlTerm"),
  1141.  
  1142.   SpecialLoadDialog(*this, "SpecialLoadDialog"),
  1143.   MangleDialog(*this, "MangleDialog"),
  1144.   DefDlgProc(*this, "BWCCDefDlgProc"),
  1145.   DefGrayDlgProc(*this, "BWCCDefGrayDlgProc"),
  1146.   DefWindowProc(*this, "BWCCDefWindowProc"),
  1147.   DefMDIChildProc(*this, "BWCCDefMDIChildProc"),
  1148.   MessageBox(*this, "BWCCMessageBox"),
  1149.   GetPattern(*this, "BWCCGetPattern"),
  1150.   GetVersion(*this, "BWCCGetVersion")
  1151. {
  1152. }
  1153.  
  1154. //
  1155. // Load the Ctl3d DLL dynamically.
  1156. // Bind the member functions to the exported functions.
  1157. //
  1158. TCtl3dDll::TCtl3dDll()
  1159. :
  1160.   TModule(Ctl3dDllName, true, true),
  1161.  
  1162.   Register(*this, "Ctl3dRegister"),
  1163.   Unregister(*this, "Ctl3dUnregister"),
  1164.   AutoSubclass(*this, "Ctl3dAutoSubclass"),
  1165.   CtlColorEx(*this, "Ctl3dCtlColorEx"),
  1166.   SubclassDlg(*this, "Ctl3dSubclassDlg"),
  1167.   SubclassDlgEx(*this, "Ctl3dSubclassDlgEx"),
  1168.   GetVer(*this, "Ctl3dGetVer"),
  1169.   Enabled(*this, "Ctl3dEnabled"),
  1170.   ColorChange(*this, "Ctl3dColorChange"),
  1171.   SubclassCtl(*this, "Ctl3dSubclassCtl"),
  1172.   DlgFramePaint(*this, "Ctl3dDlgFramePaint"),
  1173.   WinIniChange(*this, "Ctl3dWinIniChange")
  1174. {
  1175. }
  1176.  
  1177. #endif
  1178. //----------------------------------------------------------------------------
  1179. #if !defined(SECTION) || SECTION == 4
  1180.  
  1181. #if !defined(BI_NO_OBJ_STREAMING)
  1182.  
  1183. // Broken apart: IMPLEMENT_STREAMABLE1(TApplication, TModule);
  1184. // to replace the ctor
  1185. //
  1186. IMPLEMENT_STREAMABLE_CLASS(TApplication);
  1187. IMPLEMENT_CASTABLE1(TApplication, TModule);
  1188. IMPLEMENT_STREAMER(TApplication);
  1189. IMPLEMENT_STREAMABLE_POINTER(TApplication)
  1190.  
  1191. // IMPLEMENT_STREAMABLE_CTOR1(TApplication, TModule), plus TMsgThread init
  1192. //
  1193. TApplication::TApplication(StreamableInit)
  1194. :
  1195.   TModule(streamableInit),
  1196.   TMsgThread(TMsgThread::Current)
  1197. {
  1198. }
  1199.  
  1200. //
  1201. //
  1202. //
  1203. void*
  1204. TApplication::Streamer::Read(ipstream& is, uint32 /*version*/) const
  1205. {
  1206.   TApplication* o = GetObject();
  1207.   if (o != ::Module)
  1208.     is >> *::Module;   // set reference to OWL module
  1209.   return o;
  1210. }
  1211.  
  1212. //
  1213. //
  1214. //
  1215. void
  1216. TApplication::Streamer::Write(opstream& os) const
  1217. {
  1218.   TApplication* o = GetObject();
  1219.   if (o != ::Module)
  1220.     os << *::Module;    // write out reference to OWL module, no data written
  1221. }
  1222.  
  1223. #else
  1224.  
  1225. IMPLEMENT_STREAMABLE1(TApplication, TModule);
  1226.  
  1227. #endif  // if !defined(BI_NO_OBJ_STREAMING)
  1228.  
  1229. #endif  // SECTION
  1230.